#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "InetAddr.hpp"
#include "log.hpp"
#include<cstdio>

using namespace LogModule;

enum ExitCode
{
    OK = 0,
    SOCK_ERROR,
    BIND_ERROR,
    LISTEN_ERR,
    ACCEPT_ERROR,
};

const int defaultlog = 5;
class Socket
{
public:
    virtual void SocketOrDie() = 0;
    virtual void BindOrDie(uint16_t port) = 0;
    virtual void ListenOrDie(int backlog) = 0;
    virtual std::shared_ptr<Socket> AcceptOrDie(InetAddr* cil)= 0;
    virtual void Close()=0;
    virtual int Recv(std::string *inbuffer)=0;
    virtual int Send(std::string send_message)=0;
    virtual int Connect( std::string& serve_ip, uint16_t& serve_port)=0;

    void BuildTCPSocket(uint16_t port,int backlog=defaultlog)
    {
        SocketOrDie();
        BindOrDie(port);
        ListenOrDie(backlog);
    }

    void Build_client_TCPSocket()
    {
        SocketOrDie();
    }
};

const int defaultsockfd=-1;
class TCPSocket : public Socket
{
public:
    TCPSocket()
    {
        _sockfd=defaultsockfd;
    }
    TCPSocket(int sockfd)
    {
        _sockfd=sockfd;
    }
    ~TCPSocket()
    {
    }
    void SocketOrDie() override
    {
        // 创建套接字：
        int ret = socket(AF_INET, SOCK_STREAM, 0);
        if (ret == -1)
        {
            LOG(LogLevel::FATAL) << "socket error!!";
            exit(SOCK_ERROR);
        }
        _sockfd = ret;
        LOG(LogLevel::INFO) << "socket success!!";
    }
    void BindOrDie(uint16_t port) override
    {
        // 绑定套接字
        InetAddr local(port);
        int ret = bind(_sockfd, local.NetAddrPtr(), local.NetAddrLen());
        if (ret < 0)
        {
            LOG(LogLevel::FATAL) << "bind error!!";
            exit(BIND_ERROR);
        }
        LOG(LogLevel::INFO) << "bind success!!";
    }
    void ListenOrDie(int backlog = defaultlog) override
    {
        // 设置套接字为监听状态
        int ret = listen(_sockfd, backlog);
        if (ret < 0)
        {
            LOG(LogLevel::FATAL) << "listen error!!";
            exit(LISTEN_ERR);
        }
        LOG(LogLevel::INFO) << "listen success!!";
    }

    std::shared_ptr<Socket> AcceptOrDie(InetAddr* cli) override
    {
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        LOG(LogLevel::INFO)<<"监听套接字是: " << _sockfd;
        int sockfd=accept(_sockfd,CONV(peer),&len);
        if(sockfd<0)
        {
            LOG(LogLevel::FATAL)<<"accept fail!";
            perror("reason::");
            return nullptr;
        }
       // sleep(5);
        LOG(LogLevel::INFO)<<"accept success!";
        cli->SetAddr(peer);
        return std::make_shared<TCPSocket>(sockfd);
    }

    void Close() override
    {
        LOG(LogLevel::DEBUG)<<"关闭的套接字是:" << _sockfd;
        close(_sockfd);
        sleep(4);
    }

    int Recv(std::string *inbuffer) override
    {
        char buffer[1024];
        int ret=recv(_sockfd,buffer,sizeof(buffer)-1,0);
        if(ret>0)
        {
            buffer[ret]='\0';
            *inbuffer+=buffer;
            return 1;
        }
        else if(ret==0)
        {
           LOG(LogLevel::DEBUG)<<"客户端退出:" ;
            return 0;
        }
        else
        {
            LOG(LogLevel::DEBUG)<<"recv error!!" ;
            return -1;
        }
    }

    int Send(std::string send_message)
    {
        int ret=send(_sockfd,send_message.c_str(),send_message.size(),0);
        return ret;
    }
    int Connect(std::string& serve_ip,uint16_t& serve_port) override
    {
        InetAddr server(serve_ip,serve_port);
        int ret=connect(_sockfd,server.NetAddrPtr(),server.NetAddrLen());

        return ret;
    }
private:
    int _sockfd;
};